package com.hdu;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;

@Data
@Slf4j
public class Future<T> {

    private T result;

    public static void main(String[] args) {
        testTimeOutGet();
    }

    public static void testTimeOutGet() {
        Future<String> future = new Future<>();
        /**
         * 开一个线程去取, 该线程最多只等待1s
         */
        Thread consumeThread = new Thread(() -> {
            log.info("等待获取结果....");
            String result = future.get(1, TimeUnit.SECONDS, "default");
            log.info("成功获取结果 : {}", result);
        });

        /**
         * 开一个线程2s后放东西
         */
        Thread produceThread = new Thread(() -> {
            try {
                log.info("开始执行生产");
                TimeUnit.SECONDS.sleep(2);
                log.info("生产完成");
                future.set("hello world");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });


        // 开启
        consumeThread.start();
        produceThread.start();

        try {
            consumeThread.join();
            ;
            produceThread.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    public static void testGet() {
        Future<String> future = new Future<>();
        /**
         * 开一个线程去取
         */
        Thread consumeThread = new Thread(() -> {
            log.info("等待获取结果....");
            String result = future.get();
            log.info("成功获取结果 : {}", result);
        });


        /**
         * 开一个线程2s后放东西
         */
        Thread produceThread = new Thread(() -> {
            try {
                log.info("开始执行生产");
                TimeUnit.SECONDS.sleep(2);
                log.info("生产完成");
                future.set("hello world");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });


        // 开启
        consumeThread.start();
        produceThread.start();

        try {
            consumeThread.join();
            ;
            produceThread.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    public T get(long waitTime, TimeUnit timeUnit) {
        return get(waitTime, timeUnit, null);
    }

    public T get(long waitTime, TimeUnit timeUnit, T defaultValue) {
        synchronized (this) {
            waitTime = timeUnit.toMillis(waitTime);
            long startTime = System.currentTimeMillis();
            while (result == null) {
                if (waitTime <= 0) {
                    return defaultValue;
                }
                try {
                    this.wait(waitTime);
                    waitTime -= System.currentTimeMillis() - startTime;
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            return result;
        }
    }


    /**
     * 获得结果
     *
     * @return
     */
    public T get() {
        synchronized (this) {
            while (result == null) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            return result;
        }
    }

    /**
     * 设置结果
     */
    public void set(T result) {
        synchronized (this) {
            this.result = result;
            this.notifyAll();
        }
    }

}
